
#include <iostream>

#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif

#include <stdlib.h>
#include "glDisplay.h"
#include "Image.h"

int slices = 16;
int stacks = 16;


float  * reArrangedImage;


/* GLUT callback Handlers */

void resize(int width, int height)
{
    const float ar = (float) width / (float) height;
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity() ;
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode (GL_MODELVIEW); glPushMatrix (); glLoadIdentity (); glMatrixMode (GL_PROJECTION); glPushMatrix (); glLoadIdentity ();
    glEnable(GL_TEXTURE_2D);
    glBindTexture (GL_TEXTURE_2D, 0);

    glBegin(GL_QUADS);
        glTexCoord2f (0.0, 0.0);
        glVertex3f(-1.0, -1.0, -1.0);

        glTexCoord2f (1.0, 0.0);
        glVertex3f(1.0, -1.0, -1.0);

        glTexCoord2f (1.0, 1.0);
        glVertex3f(1.0, 1.0, -1.0);

        glTexCoord2f (0.0, 1.0);
        glVertex3f(-1.0, 1.0, -1.0);
    glEnd();

    glPopMatrix (); glMatrixMode (GL_MODELVIEW); glPopMatrix ();
    glutSwapBuffers();
}


void key(unsigned char key, int x, int y)
{
    switch (key)
    {
        case 27 :
        case 'q':
            exit(0);
            break;

        case '+':
            slices++;
            stacks++;
            break;

        case '-':
            if (slices>3 && stacks>3)
            {
                slices--;
                stacks--;
            }
            break;
    }

    glutPostRedisplay();
}

void idle(void)
{
    glutPostRedisplay();
}

void UseImage(Image &img) {
    std::cout << "Uploading image for display, array size:" << img.x*img.y*3 << std::endl;
    reArrangedImage = new float[img.x*img.y*3];
    int a,b,c;
    for (int i = 0; i < img.y; i++)
    {
        for (int j = 0; j < img.x; j++)
        {
            reArrangedImage[3*(i*img.x + j)] = img.data[j][i][0];
            reArrangedImage[3*(i*img.x + j)+1] = img.data[j][i][1];
            reArrangedImage[3*(i*img.x + j)+2] = img.data[j][i][2];
        }
    }
    glBindTexture(GL_TEXTURE_2D, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, img.x, img.y, 0, GL_RGB, GL_FLOAT, reArrangedImage);
    std::cout << "... done" << std::endl;
}

glDisplay::glDisplay(Image &img, int argc, char *argv[])
{
    std::cout << "glDisplay initiated, draws image to screen." << std::endl;
    glutInit(&argc, argv);

    glutInitWindowSize(img.x,img.y);
    glutInitWindowPosition(10,10);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("expTracer");

    glutReshapeFunc(resize);
    glEnable(GL_TEXTURE_2D);
    UseImage(img);
    glutDisplayFunc(display);
    glutKeyboardFunc(key);
    glutIdleFunc(idle);

    glClearColor(1,1,1,1);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);

    glutMainLoop();
}
